local skynet = require "skynet"

local modules
local MODS_ENV_KEY = "__MODULES"

local M = {}
function M.getModules()
    if modules then
        return modules
    end

    local modules = skynet.getenvt(MODS_ENV_KEY)
    if modules then
        return modules
    end

    local lsFd = io.popen("ls modules", "r")
    local lsStr = lsFd:read("*a")
    io.close(lsFd)

    modules = {}
    local idx = 1
    while idx <= #lsStr do
        local endIdx = string.find(lsStr, "\n", idx)
        if not endIdx then
            break
        end

        table.insert(modules, lsStr:sub(idx, endIdx - 1))
        idx = endIdx + 1
    end

    skynet.setenv(MODS_ENV_KEY, table.dump(modules))
    return modules
end

function M.foreach(func)
    local mods = M.getModules()
    table.foreach(mods, func)
end

local function normailze(mod)
    return mod:gsub("^%l", string.upper)
end

function M.normailze(mod)
    return normailze(mod)
end

---@param mod string 模块名
---@param file_type string  文件类型
---@param lua boolean    是否为lua路径(lua路径则分隔符为.)
---@return string 文件路径(不包含文件后缀名)
function M.path(mod, fileType, lua)
    fileType = fileType:gsub("^%l", string.upper)
    return lua and string.format("modules.%s.%s%s", mod, normailze(mod), fileType) or
               string.format("modules/%s/%s%s", mod, normailze(mod), fileType)
end

function M.protoPath(mod, lua)
    return M.path(mod, "Proto", lua)
end

function M.protobufPath(mod)
    return string.format("modules/%s/%s.pb", mod, normailze(mod))
end

function M.handlerPath(mod, lua)
    return M.path(mod, "Handler", lua)
end

function M.listenerPath(mod, lua)
    return M.path(mod, "Listener", lua)
end

function M.servicePath(mod, lua)
    return M.path(mod, "Service", lua)
end

function M.APIPath(mod, lua)
    return M.path(mod, "API", lua)
end

function M.allProtoMod()
    return skynet.getenvt("__MOD_PROTOS")
end

function M.allProtobufMod()
    return skynet.getenvt("__MOD_PROTOBUFS")
end

function M.allHandlerMod()
    return skynet.getenvt("__MOD_HANDLERS")
end

function M.allListenerMod()
    return skynet.getenvt("__MOD_LISTENERS")
end

function M.allServiceMod()
    return skynet.getenvt("__MOD_SERVICES")
end

function M.allAPIMod()
    return skynet.getenvt("__MOD_APIS")
end

function M.init()
    local ioexists = io.exists
    local tableinsert = table.insert

    local inited = skynet.getenvb("__MOD_INITED")
    if inited then
        return
    end

    local mods = M.getModules()
    local pbMods = {}
    local protoMods = {}
    local handlerMods = {}
    local listenerMods = {}
    local serviceMods = {}
    local APIMods = {}
    for _, mod in pairs(mods) do
        if ioexists(M.protobufPath(mod)) then
            tableinsert(pbMods, mod)
        end

        if ioexists(M.protoPath(mod) .. ".lua") then
            tableinsert(protoMods, mod)
        end

        if ioexists(M.handlerPath(mod) .. ".lua") then
            tableinsert(handlerMods, mod)
        end

        if ioexists(M.listenerPath(mod) .. ".lua") then
            tableinsert(listenerMods, mod)
        end

        if ioexists(M.servicePath(mod) .. ".lua") then
            tableinsert(serviceMods, mod)
        end

        if ioexists(M.APIPath(mod) .. ".lua") then
            tableinsert(APIMods, mod)
        end
    end

    skynet.setenv("__MOD_INITED", "true")

    skynet.setenv("__MOD_PROTOBUFS", table.dump(pbMods))
    skynet.setenv("__MOD_PROTOS", table.dump(protoMods))
    skynet.setenv("__MOD_HANDLERS", table.dump(handlerMods))
    skynet.setenv("__MOD_LISTENERS", table.dump(listenerMods))
    skynet.setenv("__MOD_SERVICES", table.dump(serviceMods))
    skynet.setenv("__MOD_APIS", table.dump(APIMods))
end

return M
